//
// File:   MeshImpl_grid3d.h
// Author: boyan
//
// Created on August 28, 2008, 5:43 PM
//

#ifndef _MESHIMPL_GRID3D_H
#define	_MESHIMPL_GRID3D_H

#include "grid3d.h"

#include <MeshInterface.hpp>
#include <MsqError.hpp>
#include <MeshImplTags.hpp>

class Mesh_grid3d : public Mesquite::Mesh
{
public:
    //********* Functions that are NOT inherited ************

    //    Mesh_grid3d() :
    //    myTags(new Mesquite::MeshImplTags),
    //    fixed_DIR(false),
    //    fixed_onbdry(true),
    //    my_grid(NULL),
    //    vertex_bytes(NULL),
    //    own_my_grid(false)
    //    {
    //    }
    //

    Mesh_grid3d(grid3d_t &grid, bool own = false) :
    myTags(new Mesquite::MeshImplTags),
    fixed_DIR(false),
    fixed_onbdry(true),
    my_grid(&grid),
    vertex_bytes(NULL),
    own_my_grid(own)
    {
    }

    virtual ~Mesh_grid3d();

    void read_g3t(const char *file_name, Mesquite::MsqError& err);
    void write_g3t(const char *file_name, Mesquite::MsqError& err);
    void read_g3b(const char *file_name, Mesquite::MsqError& err);
    void write_g3b(const char *file_name, Mesquite::MsqError& err);

    grid3d_t *grid3d(void) const
    {
        return my_grid;
    };

    inline void own_grid(void)
    {
        own_my_grid = true;
    };

    inline void set_fixed_DIR(bool val = true)
    {
        fixed_DIR = val;
    }

    inline void set_fixed_onbdry(bool val = true)
    {
        fixed_onbdry = val;
    }

    static inline Mesquite::Mesh::EntityHandle node2handle(int nid)
    {
        return (Mesquite::Mesh::EntityHandle) (2 * nid); // nodes have even handles
    }

    static inline Mesquite::Mesh::EntityHandle elem2handle(int nid)
    {
        return (Mesquite::Mesh::EntityHandle) (2 * nid + 1); // elems have odd handles
    }

    static inline int handle2node(Mesquite::Mesh::EntityHandle h)
    {
        size_t hh = (size_t) h;
        return hh / 2;
    }

    static inline int handle2elem(Mesquite::Mesh::EntityHandle h)
    {
        size_t hh = (size_t) h;
        return hh / 2;
    }

    static inline bool is_handle_of_node(Mesquite::Mesh::EntityHandle h)
    {
        size_t hh = (size_t) h;
        return hh % 2 == 0; // nodes have even handles
    }

    static inline bool is_handle_of_elem(Mesquite::Mesh::EntityHandle h)
    {
        size_t hh = (size_t) h;
        return hh % 2 != 0; // elems have odd handles
    }

    //******** Implementations of inherited functions *********//

    inline virtual int get_geometric_dimension(Mesquite::MsqError &err)
    {
        return 3;
    }

    virtual void get_all_elements(msq_std::vector<ElementHandle>& elements,
                                  Mesquite::MsqError& err);
    virtual void get_all_vertices(msq_std::vector<VertexHandle>& vertices,
                                  Mesquite::MsqError& err);

    virtual void vertices_get_fixed_flag(const VertexHandle vert_array[],
                                         bool fixed_flag_array[], size_t num_vtx,
                                         Mesquite::MsqError &err);
    virtual void vertices_get_coordinates(const VertexHandle vert_array[],
                                          Mesquite::MsqVertex* coordinates, size_t num_vtx,
                                          Mesquite::MsqError &err);
    virtual void vertex_set_coordinates(VertexHandle vertex,
                                        const Mesquite::Vector3D &coordinates, Mesquite::MsqError &err);
    virtual void vertex_set_byte(VertexHandle vertex,
                                 unsigned char byte, Mesquite::MsqError &err);
    virtual void vertices_set_byte(const VertexHandle *vert_array,
                                   const unsigned char *byte_array, size_t array_size,
                                   Mesquite::MsqError &err);
    virtual void vertex_get_byte(const VertexHandle vertex,
                                 unsigned char *byte, Mesquite::MsqError &err);
    virtual void vertices_get_byte(const VertexHandle *vertex,
                                   unsigned char *byte_array, size_t array_size, Mesquite::MsqError &err);
    virtual void vertices_get_attached_elements(
                                                const VertexHandle* vertex_array, size_t num_vertex,
                                                msq_std::vector<ElementHandle>& elements,
                                                msq_std::vector<size_t>& offsets, Mesquite::MsqError& err);
    virtual void elements_get_attached_vertices(
                                                const ElementHandle *elem_handles, size_t num_elems,
                                                msq_std::vector<VertexHandle>& vert_handles,
                                                msq_std::vector<size_t>& offsets, Mesquite::MsqError &err);
    virtual void elements_get_topologies(
                                         const ElementHandle *element_handle_array,
                                         Mesquite::EntityTopology *element_topologies,
                                         size_t num_elements, Mesquite::MsqError &err);
    virtual void release_entity_handles(const EntityHandle *handle_array,
                                        size_t num_handles, Mesquite::MsqError &err);
    virtual void release();

    virtual Mesquite::VertexIterator* vertex_iterator(Mesquite::MsqError &err)
    {
        return new Mesh_grid3d_Iterator<node2handle > (my_grid->NN);
    };

    virtual Mesquite::ElementIterator* element_iterator(Mesquite::MsqError &err)
    {
        return new Mesh_grid3d_Iterator<elem2handle > (my_grid->NEL);
    };


private:
    Mesquite::MeshImplTags *myTags;
    bool fixed_DIR, fixed_onbdry;

public:
    virtual Mesquite::TagHandle tag_create(const msq_std::string& tag_name,
                                           TagType type, unsigned length, const void* default_value,
                                           Mesquite::MsqError &err);
    virtual void tag_delete(Mesquite::TagHandle handle,
                            Mesquite::MsqError& err);
    virtual Mesquite::TagHandle tag_get(const msq_std::string& name,
                                        Mesquite::MsqError& err);
    virtual void tag_properties(Mesquite::TagHandle handle,
                                msq_std::string& name_out, TagType& type_out, unsigned& length_out,
                                Mesquite::MsqError& err);
    virtual void tag_set_element_data(Mesquite::TagHandle handle,
                                      size_t num_elems, const ElementHandle* elem_array,
                                      const void* tag_data, Mesquite::MsqError& err);
    virtual void tag_set_vertex_data(Mesquite::TagHandle handle,
                                     size_t num_elems, const VertexHandle* node_array,
                                     const void* tag_data, Mesquite::MsqError& err);
    virtual void tag_get_element_data(Mesquite::TagHandle handle,
                                      size_t num_elems, const ElementHandle* elem_array,
                                      void* tag_data, Mesquite::MsqError& err);
    virtual void tag_get_vertex_data(Mesquite::TagHandle handle,
                                     size_t num_elems, const VertexHandle* node_array,
                                     void* tag_data, Mesquite::MsqError& err);

protected:
    grid3d_t *my_grid;
private:
    unsigned char *vertex_bytes;
    bool own_my_grid;
    void calloc_vertex_bytes(Mesquite::MsqError &err);

protected:

    template <Mesquite::Mesh::EntityHandle(*index2handle)(int) >
    class Mesh_grid3d_Iterator : public Mesquite::EntityIterator
    {
    protected:
        int number_of_entities;
        int current_position;

    public:

        Mesh_grid3d_Iterator(int size)
        : number_of_entities(size), current_position(0)
        {
        };

        virtual void restart()
        {
            current_position = 0;
        };

        virtual Mesquite::Mesh::EntityHandle operator*() const
        {
            return index2handle(current_position);
        };

        virtual void operator++()
        {
            ++current_position;
        };

        virtual bool is_at_end() const
        {
            return current_position >= number_of_entities;
        };

        virtual ~Mesh_grid3d_Iterator()
        {
        };
    };
};

#endif	/* _MESHIMPL_GRID3D_H */

